<?php

namespace App\Services;

use App\Exceptions\AppException;
use App\Models\Article;
use App\Models\Comment;
use Illuminate\Support\Str;

class ArticleService
{

    /**
     * 从文章详情截取255字作为文章摘要
     * @param string $content 文章详情
     * @return string
     */
    private function getExcerptFromContent(string $content)
    {
        $content = strip_tags($content);
        $content = preg_replace("/\n+/", "\n", $content);
        $content = preg_replace('/&[a-z]+;/', '', $content);
        $excerpt = Str::limit($content, 255);
        $excerpt = '<p>' . $excerpt . '</p>';
        return $excerpt;
    }

    /**
     * 按状态统计文章数
     * @param int $status
     * @return int
     */
    public function getCountByStatus(int $status)
    {
        return Article::where('status', $status)->count();
    }

    /**
     * 分页获取文章列表，同时关联获取所属分类、评论数量
     * @param array $where
     * @param int $limit
     * @param string $columns
     * @return array
     */
    public function getList(array $where = [], int $limit = 15, string $columns = '*')
    {
        $result = Article::where($where)
            ->selectRaw($columns)
            ->with(['category' => function ($query) {
                $query->select('id', 'name', 'alias');
            }])
            ->withCount('comments')
            ->orderBy('id', 'desc')
            ->paginate($limit);

        return [
            'items' => $result->items(),
            'total' => $result->total(),
            'limit' => $limit,
        ];
    }

    /**
     * 按阅读量降序获取文章列表
     * @param int $limit
     * @return Article[]
     */
    public function getReadRank(int $limit)
    {
        return Article::where('status', 1)
            ->select('id', 'title', 'published_at')
            ->orderBy('read_num', 'desc')
            ->limit($limit)
            ->get();
    }

    /**
     * 按发布时间降序获取文章列表
     * @param int $limit
     * @return Article[]
     */
    public function getNewRank(int $limit)
    {
        return Article::where('status', 1)
            ->select('id', 'title', 'published_at', 'updated_at')
            ->orderBy('updated_at', 'desc')
            ->limit($limit)
            ->get();
    }

    /**
     * 获取文章归档年月列表
     * @return Article[]
     */
    public function getArchiveGroups()
    {
        $archives = Article::where('status', 1)
            ->selectRaw("count(1) as num, from_unixtime(published_at,'%Y-%m') as ym")
            ->groupBy('ym')
            ->orderBy('ym', 'desc')
            ->get();

        foreach ($archives as $archive) {
            $archive->month_time = strtotime($archive->ym);
            $archive->archive_url = date('/Y/m', $archive->month_time);
        }

        return $archives;
    }

    /**
     * 新增文章
     * @param array $data
     */
    public function add(array $data)
    {
        if ($data['status'] == 1) {
            $data['published_at'] = time();
        } elseif ($data['status'] == 2) {
            $data['deleted_at'] = time();
        }

        if (empty($data['excerpt'])) {
            $data['excerpt'] = $this->getExcerptFromContent($data['content']);
        }

        $article = new Article($data);
        $article->save();
    }

    /**
     * 获取文章
     * @param int $id
     * @return Article
     */
    public function find(int $id)
    {
        return Article::findOrFail($id);
    }

    /**
     * 更新文章
     * @param array $data
     * @return Article
     */
    public function edit(array $data)
    {
        $article = Article::findOrFail($data['id']);

        //状态有变更
        if ($article->status != $data['status']) {
            if ($data['status'] == 1) {
                $data['published_at'] = time();
                $data['deleted_at'] = 0;
            } elseif ($data['status'] == 2) {
                $data['published_at'] = 0;
                $data['deleted_at'] = time();
            } else {
                $data['published_at'] = 0;
                $data['deleted_at'] = 0;
            }
        }

        if (empty($data['excerpt'])) {
            $data['excerpt'] = $this->getExcerptFromContent($data['content']);
        }

        $article->fill($data);
        $article->save();

        return $article;
    }

    /**
     * 删除文章
     * @param int $id
     * @param int $type 删除类型：0软删除，1永久删除
     * @throws AppException
     */
    public function del(int $id, int $type)
    {
        $article = Article::findOrFail($id);

        if ($type == 0) {
            if ($article->status == 2) {
                throw new AppException('状态无需变更');
            }
            $article->published_at = 0;
            $article->deleted_at = time();
            $article->status = 2;
            $article->save();
        } else {
            $article->delete();
            Comment::where('article_id', $id)->delete();
        }
    }

    /**
     * 用于前台展示文章
     * @param int $id
     * @return Article
     * @throws AppException
     */
    public function show(int $id)
    {
        $article = Article::where('id', $id)
            ->where('status', 1)
            ->with(['category' => function ($query) {
                $query->select('id', 'name', 'alias');
            }])
            ->with(['comments' => function ($query) {
                $query->orderBy('id', 'desc');
            }])
            ->first();

        if (!$article) {
            throw new AppException('文章不存在');
        }

        return $article;
    }

}
